package com.coincalf.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.coincalf.dto.UserDetailsMapper;
import com.coincalf.entity.User;
import com.coincalf.feign.RandCodeServiceClient;
import com.coincalf.framework.constants.Constant;
import com.coincalf.framework.enums.SmsTemplate;
import com.coincalf.framework.exception.GlobalDefaultException;
import com.coincalf.framework.security.TokenProvider;
import com.coincalf.framework.security.UserDetails;
import com.coincalf.framework.utils.TokenUtil;
import com.coincalf.service.UserDetailsService;
import com.coincalf.service.UserService;
import com.coincalf.web.vo.UserLoginForm;
import com.google.common.base.Strings;
import com.warrenstrange.googleauth.GoogleAuthenticator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author qiang
 */
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private TokenProvider tokenProvider;
    @Autowired
    private UserService userService;
    @Autowired
    private RandCodeServiceClient randCodeServiceClient;

    /**
     * 超时时间
     */
    @Value("${jwt.expire}")
    private long expire;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.selectByUsername(username);
        UserDetails userDetails = UserDetailsMapper.INSTANCE.toUserDetails(user);
        if (!Optional.ofNullable(userDetails).isPresent()) {
            throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username));
        }
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        userDetails.setAuthorities(authorities);
        return userDetails;
    }

    /**
     * 用户登录(支持用户名、手机、邮箱登录)
     *
     * @param form
     * @return
     */
    @Override
    public UserDetails login(UserLoginForm form) {
        User user = userService.selectByUsername(form.getUsername());
        if (!Optional.ofNullable(user).isPresent()) {
            log.error("账号不存在");
            throw new GlobalDefaultException(2018);
        }
        /*boolean flag = randCodeServiceClient.verify(SmsTemplate.LOGIN.getCode(), form.getUsername(), form.getValidateCode());
        if (!flag) {
            //验证码错误
            throw new GlobalDefaultException(20007);
        }*/
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(form.getUsername(), form.getPassword());
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        if (!form.getType().equals(userDetails.getType())) {
            // 用户类型错误
            throw new GlobalDefaultException(40016);
        }
        // 如果开启了GA验证
        if (!Strings.isNullOrEmpty(userDetails.getGaSecret())) {
            GoogleAuthenticator gAuth = new GoogleAuthenticator();
            if (!gAuth.authorize(userDetails.getGaSecret(), form.getGa_code())) {
                // 谷歌验证码错误，请重新输入
                throw new GlobalDefaultException(40004);
            }
        }
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = tokenProvider.createToken(userDetails);
        userDetails.setAccessToken(Constant.BEARER + accessToken);
        userDetails.setExpire(expire);
        return userDetails;
    }

    @Override
    public UserDetails oauth(String access_key, String secret) {
        EntityWrapper<User> ew = new EntityWrapper<>();
        ew.eq("access_key_id", access_key);
        ew.eq("access_key_secret", secret);
        User user = userService.selectOne(ew);
        if (Optional.ofNullable(user).isPresent()) {
            UserDetails userDetails = UserDetailsMapper.INSTANCE.toUserDetails(user);
            List<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_OPEN"));
            userDetails.setAuthorities(authorities);
            String accessToken = tokenProvider.createToken(userDetails);
            userDetails.setAccessToken(Constant.BEARER + accessToken);
            return userDetails;
        } else {
            //无效的access_key_id
            throw new GlobalDefaultException(40012);
        }
    }

    @Override
    public String refreshToken(String accessToken) {
        return Constant.BEARER + tokenProvider.refreshToken(accessToken);
    }

    @Override
    public String phpLogin(String token) {
        Map<String, Object> map = TokenUtil.parserImToken(token);
        //{"phoneCode":86,"userId":1,"iat":1611387354,"username":"15989001760","password":"123"}
        String phoneCode = (String) map.get("phoneCode");
        String userId = (String) map.get("userId");
        String username = (String) map.get("username");
        String password = (String) map.get("password");
        if (StringUtils.isBlank(phoneCode) || StringUtils.isBlank(userId)
                || StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return "请求参数不能为空";
        }
        User user = userService.selectByUsername(username);
        if (!Optional.ofNullable(user).isPresent()) {
            log.error("用户不存在");
            return "用户不存在";
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return "SUCCESS";
    }

}
